

package org.jeecg.modules.demo.Kingdee.Job;

import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import com.kingdee.bos.webapi.sdk.K3CloudApi;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.jeecg.modules.demo.DingTalk.CreateInstance;
import org.jeecg.modules.demo.DingTalk.MonthPayableOnoa.entity.MonthPayableOnoa;
import org.jeecg.modules.demo.DingTalk.MonthPayableOnoa.entity.MonthPayableOnoaItem;
import org.jeecg.modules.demo.DingTalk.MonthPayableOnoa.service.IMonthPayableOnoaService;
import org.jeecg.modules.demo.DingTalk.MonthPayableOnoa.service.IMonthPayableOnoaItemService;
import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 从金蝶API查询应付单列表并自动下推月结付款单的定时任务类
 * <p>
 * 功能：查询满足特定条件的应付单列表，并自动下推生成月结付款单、提交审核、发起钉钉审批流程，
 * 并生成外部流水号同步到相关单据中
 * 查询条件：
 * 1. 开票核销状态为完全：FOPENSTATUS='C'
 * 2. 付款条件为月结、双月结、三月结：FPAYCONDITON IN (20002,2147447,2147448)
 * 3. 付款核销状态为空：FWRITTENOFFSTATUS ='A'
 * 4. 到期日不为空：FINISHDATE IS NOT NULL
 * <p>
 * 工作流程：
 * 1. 查询符合条件的应付单列表
 * 2. 将应付单下推生成月结付款单
 * 3. 自动提交并审核月结付款单
 * 4. 按供应商分类汇总金额
 * 5. 发起钉钉审批流程
 * 6. 生成外部流水号(ext+时间戳)并更新到金蝶单据和本地数据库中
 * 7. 保存审批记录到本地数据库
 */
@Slf4j
@Component
public class KingdeeMonthPayableJob implements Job {

    @Autowired
    private CreateInstance createInstance;

    @Autowired
    private IMonthPayableOnoaService monthPayableOnoaService;
    
    @Autowired
    private IMonthPayableOnoaItemService monthPayableOnoaItemService;
    
    /**
     * 定时任务执行方法
     *
     * @param jobExecutionContext 定时任务执行上下文
     * @throws Exception 执行过程中可能抛出的异常
     */
    @SneakyThrows
    @Override
    public void execute(JobExecutionContext jobExecutionContext) {
        try {
            // 先查询符合条件的供应商列表
            // 条件：付款条件为月结、双月结、三月结：FPAYCONDITON IN (20002,2147447,2147448)
            // 获取字段：FName（名称），FSupplierId（供应商Id），FUseOrgId（使用组织）
//            querySuppliersWithPaymentConditions();

            // 查询应付单列表
            queryPayableList();

        } catch (Exception e) {
            log.error("执行金蝶应付单查询任务时发生错误: ", e);
        }
    }

    /**
     * 查询符合条件的应付单列表
     */
    private void queryPayableList() {
        try {
            // 构造查询条件
            // 开票核销状态为完全：FOPENSTATUS='C'
            // 付款条件为月结、双月结、三月结：FPAYCONDITON IN (20002,2147447,2147448)
            // 付款核销状态为空：FWRITTENOFFSTATUS ='A'
            // 到期日不为空：FINISHDATE IS NOT NULL
            String filterString = "FOPENSTATUS='C' AND FPAYCONDITON IN (20002,2147447,2147448) AND FWRITTENOFFSTATUS='A' AND FINISHDATE IS NOT NULL";

            // 设置查询字段，根据实际需要调整
            String fieldKeys = "FID,FBillNo,FOPENSTATUS,FPAYCONDITON.FName,FWRITTENOFFSTATUS,F_RBPB_Integer,FINISHDATE";

            // 构造查询JSON
            String queryJson = String.format(
                    "{\"FormId\":\"AP_Payable\",\"FieldKeys\":\"%s\",\"FilterString\":\"%s\",\"OrderString\":\"\",\"TopRowCount\":0,\"StartRow\":0,\"Limit\":2000}",
                    fieldKeys, filterString
            );

            log.info("开始查询金蝶应付单，查询条件: {}", filterString);

            // 初始化K3CloudApi并执行查询
            K3CloudApi api = new K3CloudApi();
            String resultStr = api.billQuery(queryJson);

            // 解析查询结果
            List<JSONObject> resultList = JSONArray.parseArray(resultStr, JSONObject.class);

            log.info("应付单查询完成，共找到 {} 条应付单记录", resultList.size());

            // 收集需要下推的应付单ID
            List<String> billIds = new ArrayList<>();

            // 处理查询结果
            for (JSONObject item : resultList) {
                String billId = item.getString("FID");
                String billNo = item.getString("FBillNo");
                String openStatus = item.getString("FOPENSTATUS");
                String payCondition = item.getString("FPAYCONDITON.FName");
                String writtenOffStatus = item.getString("FWRITTENOFFSTATUS");
                String finishDate = item.getString("FINISHDATE");

                log.info("应付单信息 - 单据ID: {}, 单据编号: {}, 开票核销状态: {}, 付款条件: {}, 付款核销状态: {}, 到期日: {}",
                        billId, billNo, openStatus, payCondition, writtenOffStatus, finishDate);

                // 收集应付单ID用于下推
                billIds.add(billId);
            }

            // 统一下推处理
            if (!billIds.isEmpty()) {
                pushPayableToMonthPay(billIds, api);
            }
        } catch (Exception e) {
            log.error("查询应付单列表时发生错误: ", e);
        }
    }

    /**
     * 将应付单下推到月结付款单
     *
     * @param billIds 应付单ID列表
     * @param api     金蝶API实例
     */
    private void pushPayableToMonthPay(List<String> billIds, K3CloudApi api) {
        try {
            log.info("开始下推应付单到月结付款单，共 {} 条记录", billIds.size());

            // 构造下推参数
            String ids = String.join(",", billIds);
            String pushParams = String.format(
                    "{\"Ids\": \"%s\",\"RuleId\": \"PAYABLETOMONTHPAY\",\"IsDraftWhenSaveFail\": \"true\"}",
                    ids
            );

            log.info("下推参数: {}", pushParams);

            // 执行下推操作
            String pushResult = api.push("AP_Payable", pushParams);

            // 解析下推结果
            JSONObject result = JSONObject.parseObject(pushResult);
            if (result != null && result.containsKey("Result")) {
                JSONObject resultObj = result.getJSONObject("Result");
                if (resultObj != null && resultObj.containsKey("ResponseStatus")) {
                    JSONObject responseStatus = resultObj.getJSONObject("ResponseStatus");
                    boolean isSuccess = responseStatus.getBoolean("IsSuccess");

                    if (isSuccess) {
                        log.info("应付单下推月结付款单成功，结果: {}", pushResult);

                        // 获取下推生成的单据ID并提交审核
                        JSONArray successEntitys = responseStatus.getJSONArray("SuccessEntitys");
                        if (successEntitys != null && !successEntitys.isEmpty()) {
                            List<String> createdBillIds = new ArrayList<>();
                            List<String> createdBillNumbers = new ArrayList<>();
                            for (int i = 0; i < successEntitys.size(); i++) {
                                JSONObject entity = successEntitys.getJSONObject(i);
                                String createdBillId = entity.getString("Id");
                                String createdBillNumber = entity.getString("Number");
                                if (createdBillId != null && !createdBillId.isEmpty()) {
                                    createdBillIds.add(createdBillId);
                                    createdBillNumbers.add(createdBillNumber);
                                }
                            }
                            
                            if (!createdBillIds.isEmpty()) {
                                // 在提交审核之前添加单据体数据
                                addBillEntryData(createdBillIds, api);
                                
                                submitAndAuditBills(createdBillIds, createdBillNumbers, api);
                            }
                        }
                    } else {
                        log.error("应付单下推月结付款单失败，结果: {}", pushResult);
                    }
                }
            } else {
                log.error("应付单下推月结付款单返回结果格式异常: {}", pushResult);
            }
        } catch (Exception e) {
            log.error("应付单下推月结付款单时发生错误: ", e);
        }
    }

    /**
     * 添加单据体数据到生成的月结付款单中
     *
     * @param billIds  下推生成的单据ID列表
     * @param api      金蝶API实例
     */
    private void addBillEntryData(List<String> billIds, K3CloudApi api) {
        try {
            for (String billId : billIds) {
                try {
                    // 首先查询单据的供应商信息和付款金额
                    String queryJson = String.format(
                            "{\"FormId\":\"NHOV_MONTH_PAYABLE\",\"FieldKeys\":\"FID,FSupplier.FNumber,FSupplier.FName,FPayableAmt\",\"FilterString\":\"FID=%s\",\"OrderString\":\"\",\"TopRowCount\":0,\"StartRow\":0,\"Limit\":100}",
                            billId
                    );
                    
                    String queryResult = api.billQuery(queryJson);
                    List<JSONObject> resultList = JSONArray.parseArray(queryResult, JSONObject.class);
                    
                    // 按供应商维度分组并计算总金额
                    Map<String, SupplierInfo> supplierMap = new HashMap<>();
                    String externalNumPrefix = "ext" + new java.text.SimpleDateFormat("yyyyMMddHHmmss").format(new java.util.Date());
                    
                    for (JSONObject item : resultList) {
                        String supplierNumber = item.getString("FSupplier.FNumber");
                        String supplierName = item.getString("FSupplier.FName");
                        double payableAmount = item.getDoubleValue("FPayableAmt");
                        
                        // 如果供应商已存在，累加金额；否则创建新条目
                        if (supplierMap.containsKey(supplierNumber)) {
                            SupplierInfo info = supplierMap.get(supplierNumber);
                            info.totalAmount += payableAmount;
                        } else {
                            SupplierInfo info = new SupplierInfo();
                            info.supplierNumber = supplierNumber;
                            info.supplierName = supplierName;
                            info.totalAmount = payableAmount;
                            supplierMap.put(supplierNumber, info);
                        }
                    }
                    
                    // 构造供应商条目列表
                    StringBuilder entryListBuilder = new StringBuilder();
                    entryListBuilder.append("[\n");
                    
                    int index = 0;
                    for (Map.Entry<String, SupplierInfo> entry : supplierMap.entrySet()) {
                        if (index > 0) {
                            entryListBuilder.append(",\n");
                        }
                        
                        SupplierInfo info = entry.getValue();
                        
                        // 生成针对每个供应商的外部流水号
                        String externalNum = externalNumPrefix;
                        if (info.supplierNumber != null && !info.supplierNumber.isEmpty()) {
                            externalNum = externalNumPrefix + "_" + info.supplierNumber;
                        }
                        
                        entryListBuilder.append("  {\n")
                                .append("    \"FSupplier_S\": {\n")
                                .append("      \"FNUMBER\": \"").append(info.supplierNumber != null ? info.supplierNumber : "").append("\"\n")
                                .append("    },\n")
                                .append("    \"FSupplier_S_PAYAMT\": ").append(String.format("%.2f", info.totalAmount)).append(",\n")
                                .append("    \"FSupplier_S_BankSta\": \"未付款\",\n")
                                .append("    \"FSupplier_S_Receip\": \"未上传\",\n")
                                .append("    \"FSupplier_S_EXTNUM\": \"").append(externalNum).append("\"\n")
                                .append("  }");
                        index++;
                    }
                    entryListBuilder.append("\n]");
                    
                    // 构造更新JSON，添加单据体数据
                    String updateJson = String.format(
                            "{\n" +
                                    "\"NeedUpDateFields\": [\n" +
                                    "\"FSupplier_BankSta\",\n" +
                                    "\"FSupplier_S_PAYAMT\",\n" +
                                    "\"FSupplier_S_BankSta\",\n" +
                                    "\"FSupplier_S\",\n" +
                                    "\"FSupplier_S_Receip\",\n" +
                                    "\"FSupplier_S_EXTNUM\"\n" +
                                    "],\n" +
                                    "\"Model\": {\n" +
                                    "\"FID\": %s,\n" +
                                    "\"FSupplier_BankSta\": %s\n" +
                                    "}\n" +
                                    "}",
                            billId, entryListBuilder.toString()
                    );

                    log.info("开始更新单据 {} 添加单据体数据，更新JSON: {}", billId, updateJson);

                    // 执行更新操作
                    String resultStr = api.save("NHOV_MONTH_PAYABLE", updateJson);

                    log.info("更新单据 {} 添加单据体数据结果: {}", billId, resultStr);

                    // 解析结果
                    JSONObject result = JSONObject.parseObject(resultStr);
                    if (result != null && result.containsKey("Result")) {
                        JSONObject resultObj = result.getJSONObject("Result");
                        if (resultObj != null && resultObj.containsKey("ResponseStatus")) {
                            JSONObject responseStatus = resultObj.getJSONObject("ResponseStatus");
                            boolean isSuccess = responseStatus.getBoolean("IsSuccess");

                            if (isSuccess) {
                                log.info("成功更新单据 {} 添加单据体数据", billId);
                            } else {
                                log.error("更新单据 {} 添加单据体数据失败: {}", billId, resultStr);
                            }
                        }
                    }
                } catch (Exception e) {
                    log.error("更新单据 {} 添加单据体数据时发生错误: ", billId, e);
                }
            }
        } catch (Exception e) {
            log.error("添加单据体数据时发生错误: ", e);
        }
    }
    
    /**
     * 供应商信息内部类
     */
    private static class SupplierInfo {
        private String supplierNumber;
        private String supplierName;
        private double totalAmount;
    }

    /**
     * 提交并审核生成的单据
     *
     * @param billIds     下推生成的单据ID列表
     * @param billNumbers 下推生成的单据编号列表
     * @param api         金蝶API实例
     */
    private void submitAndAuditBills(List<String> billIds, List<String> billNumbers, K3CloudApi api) {
        try {
            for (int i = 0; i < billIds.size(); i++) {
                String billId = billIds.get(i);
                String billNumber = billNumbers.get(i);
                try {
                    // 提交单据
                    String submitParams = String.format("{\"Ids\": \"%s\"}", billId);
                    String submitResult = api.submit("NHOV_MONTH_PAYABLE", submitParams);
                    log.info("单据 {} 提交结果: {}", billId, submitResult);

                    // 解析提交结果
                    JSONObject submitResultObj = JSONObject.parseObject(submitResult);
                    if (submitResultObj != null && submitResultObj.containsKey("Result")) {
                        JSONObject submitResultResult = submitResultObj.getJSONObject("Result");
                        if (submitResultResult != null && submitResultResult.containsKey("ResponseStatus")) {
                            JSONObject responseStatus = submitResultResult.getJSONObject("ResponseStatus");
                            boolean submitSuccess = responseStatus.getBoolean("IsSuccess");

                            if (submitSuccess) {
                                // 审核单据
                                String auditParams = String.format("{\"Ids\": \"%s\"}", billId);
                                String auditResult = api.audit("NHOV_MONTH_PAYABLE", auditParams);
                                log.info("单据 {} 审核结果: {}", billId, auditResult);

                                // 根据单据编号查询详细信息并分类供应商金额
                                queryAndClassifySupplierAmounts(billNumber, billId, api);
                            } else {
                                log.error("单据 {} 提交失败: {}", billId, submitResult);
                            }
                        }
                    }
                } catch (Exception e) {
                    log.error("处理单据 {} 时发生错误: ", billId, e);
                }
            }
        } catch (Exception e) {
            log.error("提交并审核单据时发生错误: ", e);
        }
    }

    /**
     * 查询单据详情并按供应商分类金额总和，同时生成外部流水号
     *
     * @param billNo       单据编号
     * @param sourceBillId 源单据ID，用于更新外部流水号
     * @param api          金蝶API实例
     */
    private void queryAndClassifySupplierAmounts(String billNo, String sourceBillId, K3CloudApi api) {
        try {
            // 构造查询参数，直接获取FSupplier.FName、FSupplier.FNumber和FSupplier_BankSta.FSupplier_S_PAYAMT字段（已合计好的金额）
            String queryJson = String.format(
                    "{\"FormId\":\"NHOV_MONTH_PAYABLE\",\"FieldKeys\":\"FID,FBillNo,FINISHDATE,F_NHOV_OrgId_83g.FName,FSupplier_S.FName,FSupplier_S.FNumber,FSupplier_S_PAYAMT\",\"FilterString\":\"FBillNo='%s'\",\"OrderString\":\"\",\"TopRowCount\":0,\"StartRow\":0,\"Limit\":2000}",
                    billNo
            );

            log.info("开始查询月结付款单详情，单据编号: {}", billNo);

            // 执行查询
            String resultStr = api.billQuery(queryJson);

            // 解析查询结果
            List<JSONObject> resultList = JSONArray.parseArray(resultStr, JSONObject.class);

            log.info("月结付款单 {} 查询完成，共找到 {} 条记录", billNo, resultList.size());

            // 按供应商分类金额总和（直接使用已合计的金额）
            Map<String, Double> supplierAmountMap = new HashMap<>();
            // 保存供应商名称到供应商编号的映射
            Map<String, String> supplierNameToNumberMap = new HashMap<>();

            // 直接遍历结果，获取供应商名称和已合计的应付金额
            String purchaseOrgName = resultList.get(0).getString("F_NHOV_OrgId_83g.FName");
            for (JSONObject item : resultList) {
                String supplierName = item.getString("FSupplier_S.FName");
                String supplierNumber = item.getString("FSupplier_S.FNumber");
                // 直接获取已合计的金额字段
                double payableAmount = item.getDoubleValue("FSupplier_S_PAYAMT");

                // 保存供应商金额（直接使用，不累加）
                supplierAmountMap.put(supplierName, payableAmount);
                // 保存供应商编号（如果存在）
                if (supplierNumber != null && !supplierNumber.isEmpty()) {
                    supplierNameToNumberMap.put(supplierName, supplierNumber);
                }
            }

            // 构造结果列表
            List<JSONObject> result = new ArrayList<>();
            for (Map.Entry<String, Double> entry : supplierAmountMap.entrySet()) {
                JSONObject obj = new JSONObject();
                obj.put("supplierName", entry.getKey());
                obj.put("totalAmount", entry.getValue());
                result.add(obj);
            }

            log.info("单据 {} 按供应商分类金额总和: {}", billNo, result);

            // 发起钉钉审批流程
            if (!result.isEmpty()) {
                try {
                    String instanceId = createInstance.createProcessInstanceByCode(
                            "17440767709474331", // 默认用户ID，实际应用中应从配置或参数中获取
                            billNo,
                            purchaseOrgName,
                            result
                    );
                    log.info("成功发起钉钉审批流程，实例ID: {}", instanceId);
                    //服务器生成数据库记录，保留实例ID，新建定时任务检查是否已审核，同步审核状态，完成审批的审批单回去金蝶提取付款银行账号、收款账号等信息，发起银企直连付款
                    // 生成ext+当前时间戳的外部流水号
                    String externalNum = "ext" + new java.text.SimpleDateFormat("yyyyMMddHHmmss").format(new java.util.Date());
                    MonthPayableOnoa monthPayableOnoa = new MonthPayableOnoa();
                    monthPayableOnoa.setInstId(instanceId);
                    monthPayableOnoa.setMonthpayBillno(billNo);
                    monthPayableOnoa.setStatus("待审核");
                    monthPayableOnoa.setPayStatus("待付款");
                    monthPayableOnoaService.save(monthPayableOnoa);
                    
                    // 创建子表记录，设置供应商信息和付款金额
                    String mainId = monthPayableOnoa.getId();
                    List<MonthPayableOnoaItem> items = new ArrayList<>();
                    for (Map.Entry<String, Double> entry : supplierAmountMap.entrySet()) {
                        MonthPayableOnoaItem item = new MonthPayableOnoaItem();
                        item.setMainId(mainId);
                        item.setSupplier(entry.getKey());
                        item.setAmt(new java.math.BigDecimal(entry.getValue()));
                        // 设置供应商编号（如果存在）
                        String supplierNumber = supplierNameToNumberMap.get(entry.getKey());
                        if (supplierNumber != null) {
                            item.setSupplierNo(supplierNumber);
                        }
                        // 设置外部流水号
                        item.setExtno(externalNum+supplierNumber);
                        items.add(item);
                    }
                    monthPayableOnoaItemService.saveBatch(items);

                    // 更新金蝶月结汇总单据中的F_externalNum字段
                    updateKingdeeMonthPayableExternalNum(sourceBillId, externalNum, api);
                } catch (Exception e) {
                    log.error("发起钉钉审批流程失败，单据编号: {}", billNo, e);
                }
            }

        } catch (Exception e) {
            log.error("查询并分类供应商金额时发生错误，单据编号: {}", billNo, e);
        }
    }

    /**
     * 更新金蝶月结汇总单据中的外部流水号字段
     *
     * @param billId      金蝶单据ID
     * @param externalNum 外部流水号，格式为ext+yyyyMMddHHmmss
     * @param api         金蝶API实例
     */
    private void updateKingdeeMonthPayableExternalNum(String billId, String externalNum, K3CloudApi api) {
        try {
            // 构造更新JSON
            String updateJson = String.format(
                    "{\n" +
                            "\"NeedUpDateFields\": [\n" +
                            "\"F_externalNum\"\n" +
                            "],\n" +
                            "\"IsDeleteEntry\": \"true\",\n" +
                            "\"Model\": {\n" +
                            "\"FID\": %s,\n" +
                            "\"F_externalNum\": \"%s\"\n" +
                            "}\n" +
                            "}",
                    billId, externalNum
            );

            log.debug("准备更新金蝶月结汇总单据的外部流水号，更新JSON: {}", updateJson);

            // 执行更新操作
            String resultStr = api.save("NHOV_MONTH_PAYABLE", updateJson);

            log.debug("更新结果: {}", resultStr);

            // 解析结果
            JSONObject result = JSONObject.parseObject(resultStr);
            if (result != null && result.containsKey("Result")) {
                JSONObject resultObj = result.getJSONObject("Result");
                if (resultObj != null && resultObj.containsKey("ResponseStatus")) {
                    JSONObject responseStatus = resultObj.getJSONObject("ResponseStatus");
                    boolean isSuccess = responseStatus.getBoolean("IsSuccess");

                    if (isSuccess) {
                        log.info("成功更新金蝶月结汇总单据 {} 的外部流水号为 {}", billId, externalNum);
                    } else {
                        log.error("更新金蝶月结汇总单据 {} 的外部流水号失败: {}", billId, resultStr);
                    }
                }
            }
        } catch (Exception e) {
            log.error("更新金蝶月结汇总单据 {} 的外部流水号时发生错误: ", billId, e);
        }
    }
}